//线程池的设计其实可以向进程池学习\
在设计线程池时，我们最主要的两个成员变量为：共享资源和N个新线程\
剩下其他的成员变量都是基于这两者来进行增补的\
而成员函数主要是 主线程派发任务 和 新线程拿到任务并处理\
其他成员函数自行增补
template <class T>
class ThreadPool;
#pragma once
#include <iostream>
#include <pthread.h>
#include <queue>  //用作 共享资源
#include <vector> //用作 存放线程们
#include "Threads.hpp"
#include "ProtectResourse.hpp"
#include "Log.hpp"
#define THREADSIZE 5 // 线程组中线程的个数
// 这里模版给的是共享资源的内容类型，可以派发内置类型，也可以派发自定义类型
template <class T>
class ThreadPool
{
public:
    //构造函数【OK】
    ThreadPool(int size = THREADSIZE)
        : _thread_size(size)
    {
        // 初始化线程组
        for (int i = 0; i < size; ++i)
        {
            _threads.emplace_back
            (
                //////////////////////////////////////////
                //////////// 重点 ////////////////////////
                std::bind(&ThreadPool<T>::Run, 
                          this, 
                          std::placeholders::_1, 
                          std::placeholders::_2)
                , 0
            );
        }

        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    //析构函数【OK】
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    // 主线程派发任务【OK】
    void Push(T &task)
    {
        ProtectResourse protect(&_mutex);
        {
            static int i = 0;
            _shared_resourse.push(task);
            Log log;
            log.LogMessage(ClassFile, Debug + i++, 
                           "main thread push a task : %s\n", task.TaskPrint().c_str());
            i %= 4;
            One_Thread_Wakeup();
        }
    }
    
    // 线程组执行任务【OK】
    void Start_Task()
    {
        for (auto &e : _threads)
        {
            e.Start();
        }
    }

    // 回收线程组【OK】
    void Join_Threads()
    {
        for (auto &e : _threads)
        {
            e.Join();
        }
    }

private:
    std::queue<T> _shared_resourse;            // 存放任务的共享资源
    int _thread_size;                          // 线程组中线程的个数
    std::vector< Thread<void* ,int> > _threads; // 线程组
    pthread_mutex_t _mutex;                    // 线程组之间互斥访问共享资源的锁
    pthread_cond_t _cond;                      // 主线程与线程组之间要保持同步&&互斥时使用的条件变量

////////////////////////////////////////////////////////////////////////////
    void *Run(std::string name, int arg)   //重点！！！！！！！
    {
        static int i = 0;
        T task;
        while (true)
        {
            {
            	ProtectResourse protect(&_mutex);
                while(_shared_resourse.empty())
                {
                    Thread_Wait();
                }

                // 拿任务
                task = _shared_resourse.front();
                _shared_resourse.pop();
            }
            // 处理任务
            task.Run();
            Log log;
            log.LogMessage(ClassFile, Debug + i++, 
                           "%s : %s\n", name.c_str(),  task.ResultPrint().c_str());
            i %= 4;
        }
        return nullptr;
    }

    //唤醒一个线程 【OK】
    void One_Thread_Wakeup()
    {
        pthread_cond_signal(&_cond);
    }
    //唤醒所有线程 【OK】
    void All_Thread_Wakeup()
    {
        pthread_cond_broadcast(&_cond);
    }
    //没有资源了，让线程组等待 【OK】
    void Thread_Wait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
};
